package com.tencent.mtt.supportui.utils.struct;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

/**
 * Created by leonardgong on 2017/12/7 0007.
 */

/**
 * ArrayMap is a generic key->value mapping data structure that is
 * designed to be more memory efficient than a traditional
 * {@link java.util.HashMap},
 * this implementation is a version of the platform's
 * {@link android.util.ArrayMap} that can be used on older versions of the
 * platform.
 * It keeps its mappings in an array data structure -- an integer array of hash
 * codes for each item, and an Object array of the key/value pairs. This allows
 * it to
 * avoid having to create an extra object for every entry put in to the map, and
 * it
 * also tries to control the growth of the size of these arrays more
 * aggressively
 * (since growing them only requires copying the entries in the array, not
 * rebuilding
 * a hash map).
 *
 * <p>
 * If you don't need the standard Java container APIs provided here (iterators
 * etc),
 * consider using {@link SimpleArrayMap} instead.
 * </p>
 *
 * <p>
 * Note that this implementation is not intended to be appropriate for data
 * structures
 * that may contain large numbers of items. It is generally slower than a
 * traditional
 * HashMap, since lookups require a binary search and adds and removes require
 * inserting
 * and deleting entries in the array. For containers holding up to hundreds of
 * items,
 * the performance difference is not significant, less than 50%.
 * </p>
 *
 * <p>
 * Because this container is intended to better balance memory use, unlike most
 * other
 * standard Java containers it will shrink its array as items are removed from
 * it. Currently
 * you have no control over this shrinking -- if you set a capacity and then
 * remove an
 * item, it may reduce the capacity to better match the current size. In the
 * future an
 * explicit call to set the capacity should turn off this aggressive shrinking
 * behavior.
 * </p>
 *
 * Added in API level 19
 */
public class ArrayMap<K, V> extends SimpleArrayMap<K, V> implements Map<K, V>
{
	MapCollections<K, V> mCollections;

	public ArrayMap()
	{
		super();
	}

	/**
	 * Create a new ArrayMap with a given initial capacity.
	 */
	public ArrayMap(int capacity)
	{
		super(capacity);
	}

	/**
	 * Create a new ArrayMap with the mappings from the given ArrayMap.
	 */
	public ArrayMap(SimpleArrayMap map)
	{
		super(map);
	}

	private MapCollections<K, V> getCollection()
	{
		if (mCollections == null)
		{
			mCollections = new MapCollections<K, V>()
			{
				@Override
				protected int colGetSize()
				{
					return mSize;
				}

				@Override
				protected Object colGetEntry(int index, int offset)
				{
					return mArray[(index << 1) + offset];
				}

				@Override
				protected int colIndexOfKey(Object key)
				{
					return key == null ? indexOfNull() : indexOf(key, key.hashCode());
				}

				@Override
				protected int colIndexOfValue(Object value)
				{
					return indexOfValue(value);
				}

				@Override
				protected Map<K, V> colGetMap()
				{
					return ArrayMap.this;
				}

				@Override
				protected void colPut(K key, V value)
				{
					put(key, value);
				}

				@Override
				protected V colSetValue(int index, V value)
				{
					return setValueAt(index, value);
				}

				@Override
				protected void colRemoveAt(int index)
				{
					removeAt(index);
				}

				@Override
				protected void colClear()
				{
					clear();
				}
			};
		}
		return mCollections;
	}

	/**
	 * Determine if the array map contains all of the keys in the given collection.
	 * 
	 * @param collection The collection whose contents are to be checked against.
	 * @return Returns true if this array map contains a key for every entry
	 *         in <var>collection</var>, else returns false.
	 */
	public boolean containsAll(Collection<?> collection)
	{
		return MapCollections.containsAllHelper(this, collection);
	}

	/**
	 * Perform a {@link #put(Object, Object)} of all key/value pairs in
	 * <var>map</var>
	 * 
	 * @param map The map whose contents are to be retrieved.
	 */
	@Override
	public void putAll(Map<? extends K, ? extends V> map)
	{
		ensureCapacity(mSize + map.size());
		for (Entry<? extends K, ? extends V> entry : map.entrySet())
		{
			put(entry.getKey(), entry.getValue());
		}
	}

	/**
	 * Remove all keys in the array map that exist in the given collection.
	 *
	 * @param collection The collection whose contents are to be used to remove
	 *            keys.
	 * @return Returns true if any keys were removed from the array map, else false.
	 */
	public boolean removeAll(Collection<?> collection)
	{
		return MapCollections.removeAllHelper(this, collection);
	}

	/**
	 * Remove all keys in the array map that do <b>not</b> exist in the given
	 * collection.
	 *
	 * @param collection The collection whose contents are to be used to determine
	 *            which
	 *            keys to keep.
	 * @return Returns true if any keys were removed from the array map, else false.
	 */
	public boolean retainAll(Collection<?> collection)
	{
		return MapCollections.retainAllHelper(this, collection);
	}

	/**
	 * Return a {@link Set} for iterating over and interacting with all
	 * mappings
	 * in the array map.
	 *
	 * <p>
	 * <b>Note:</b> this is a very inefficient way to access the array contents, it
	 * requires generating a number of temporary objects.
	 * </p>
	 *
	 * <p>
	 * <b>Note:</b>
	 * </p>
	 * the semantics of this
	 * Set are subtly different than that of a {@link java.util.HashMap}: most
	 * important,
	 * the {@link Entry Map.Entry} object returned by its iterator is
	 * a single
	 * object that exists for the entire iterator, so you can <b>not</b> hold on to
	 * it
	 * after calling {@link java.util.Iterator#next() Iterator.next}.
	 * </p>
	 */
	@Override
	public Set<Entry<K, V>> entrySet()
	{
		return getCollection().getEntrySet();
	}

	/**
	 * Return a {@link Set} for iterating over and interacting with all
	 * keys
	 * in the array map.
	 *
	 * <p>
	 * <b>Note:</b> this is a fairly inefficient way to access the array contents,
	 * it
	 * requires generating a number of temporary objects.
	 * </p>
	 */
	@Override
	public Set<K> keySet()
	{
		return getCollection().getKeySet();
	}

	/**
	 * Return a {@link Collection} for iterating over and interacting with
	 * all values
	 * in the array map.
	 *
	 * <p>
	 * <b>Note:</b> this is a fairly inefficient way to access the array contents,
	 * it
	 * requires generating a number of temporary objects.
	 * </p>
	 */
	@Override
	public Collection<V> values()
	{
		return getCollection().getValues();
	}
}

